#pragma once
#include <list>


namespace PimplImplementation
{
template<typename T>
class Shared_ptr_Impl;


template<typename T>
class Weak_ptr_Impl
{
	typedef typename Shared_ptr_Impl<T>::RefCount			RefCount;
	typedef typename RefCount::ListWeakObjectRef::iterator	WeakListIterator;
public:
	Weak_ptr_Impl()
		: m_Ref( nullptr ),
		  m_Object( nullptr )
	{

	}

	Weak_ptr_Impl( const Weak_ptr_Impl<T>& o )
		: m_Ref( o.m_Ref ),
		  m_Object( o.m_Object )
	{
		// Save iterator of weak_ptr in list of reference-count-class
		SaveRegisterToReferenceList();
	}

	template<typename Y>
	Weak_ptr_Impl( const Weak_ptr_Impl<Y>& o )
		: m_Ref( reinterpret_cast<RefCount*>( o.m_Ref ) ),
		  m_Object( static_cast<T*>( o.m_Object ) )
	{
		SaveRegisterToReferenceList();
	}

	Weak_ptr_Impl( const Shared_ptr_Impl<T>& o )
		: m_Ref( o.m_Ref ),
		  m_Object( const_cast<T*>( o.m_Object ) )
	{
		SaveRegisterToReferenceList();
	}

	template<typename Y>
	Weak_ptr_Impl( const Shared_ptr_Impl<Y>& o )
		: m_Ref( reinterpret_cast<RefCount*>( o.m_Ref ) ),
		  m_Object( static_cast<T*>( o.m_Object ) )
	{
		SaveRegisterToReferenceList();
	}

	~Weak_ptr_Impl( void )
	{
		Reset();
	}

	inline long UseCount() const
	{
		if( m_Ref && !Expired() )
			return m_Ref->GetCount();
		return 0;
	}

	inline bool Expired() const
	{
		if( !m_Object && m_Ref )
			return true;
		return false;
	}

	inline bool Empty() const
	{
		return m_Object == nullptr;
	}

	inline void Reset()
	{
		SaveRemoveFromReferenceList();
		m_Ref = nullptr;
		m_Object = nullptr;
	}

	friend void swap( Weak_ptr_Impl<T>& lhs, Weak_ptr_Impl<T>& rhs ) 
	{
		// enable ADL (not necessary in our case, but good practice)
		using std::swap; 

		// by swapping the members of two classes,
		// the two classes are effectively swapped
		lhs.SaveRemoveFromReferenceList();
		rhs.SaveRemoveFromReferenceList();
		swap( lhs.m_Ref, rhs.m_Ref ); 
		swap( lhs.m_Object, rhs.m_Object );
		lhs.SaveRegisterToReferenceList();
		rhs.SaveRegisterToReferenceList();

	}

	inline const Weak_ptr_Impl<T>& operator=( Weak_ptr_Impl<T> rhs )
	{
		swap( *this, rhs );
		return *this;
	}


private:

	/*! \brief		Removes the current weak pointer from the shared_ptr::RefCount object
					only if the strong-reference pointing to, hasn't been expired
	*/
	inline void SaveRemoveFromReferenceList()
	{
		// Remove from list if shared_ptr hasn't already been destroyed
		// or on empty weak-reference
		if( m_Object && m_Ref )
			m_Ref->RemoveObservedObjectPtr( m_WeakListPos );
	}

	inline void SaveRegisterToReferenceList()
	{
		// Remove from list if shared_ptr hasn't already been destroyed
		// or on empty weak-reference
		if( m_Object && m_Ref )
			m_Ref->RegisterObservedObjectPtr( &m_Object, m_WeakListPos );
	}
	typename
	Shared_ptr_Impl<T>::RefCount*		m_Ref;
	T*									m_Object;
	WeakListIterator					m_WeakListPos;


	// allow access for only creation of Weak_ptr by Shared_ptr
	template<typename T>
	friend class Shared_ptr_Impl;
	template<typename Y>
	friend class Weak_ptr_Impl;
};

}


